home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Tele / Pete Johnson / TImport 2.0.3<source> Folder / TImport.p < prev    next >
Encoding:
Text File  |  1991-09-07  |  48.1 KB  |  1,439 lines  |  [TEXT/PJMM]

  1. program TImport (input, output);
  2.  
  3. {     Written by Pete Johnson for the Glassell Park BBS                                }
  4.  
  5. {    Version 2.0.3 (remember to adjust the VERSION constant)                        }
  6.  
  7. {    Date of last revision: 09/7/91                                                        }
  8.  
  9. {                        Change History                                                        }
  10.  
  11. {    06/02/89    Changed UserPointer array from 2000 to 3000 elements        }
  12. {    06/06/89    Changed UserPointer array to UserHandle                            }
  13. {    06/06/89    Sorting UserLog for better search speed                            }
  14. {    06/07/89    Checking 'Mail Waiting' flag in UserLog to save time                }
  15. {    06/07/89    Cleaned up cap/decap routines                                        }
  16. {    06/08/89    Cleaned up WriteLine routine and went to Toolbox file calls        }
  17. {    06/11/89    Added more Toolbox file calls                                            }
  18. {    06/12/89    All file calls now use Toolbox.                                        }
  19. {                    Empty message lines padded with two space characters.            }
  20. {    06/15/89    Compiled with new Hello Tabby Unit which recognizes 'BBS'        }
  21. {                    alias.                                                                        }
  22. {    06/17/89    Redefined Status and Section as arrays of Byte                    }
  23. {    06/18/89    Fixed bug mixing up Config & UserLog paths                        }
  24. {    06/25/89    Fixed bug with seek to set mail flag (wrote garbage to            }
  25. {                    UserLog)                                                                    }
  26. {    06/28/89    Added buffer for reading Import file                                    }
  27. {    07/02/89    Fixed AreaFix problem                                                    }
  28. {    07/23/89    Strengthened error checking to handle garbage in Generic        }
  29. {                    Import file (Version 1.332)                                            }
  30. {    10/28/89    Reduced memory demands in default settings                        }
  31. {    11/8/89        Improved error detection & recovery for Generic Import file    }
  32. {                    (version 1.5b2)                                                            }
  33. {    11/17/89    Added WaitNextEvent calls to improve MultiFinder                }
  34. {                    compatibility (version 1.5b3)                                            }
  35. {    11/18/89    Expanded error reporting into intelligible messages                }
  36. {    11/19/89    Compiled version 1.5                                                    }
  37. {    11/29/89    Added Point ^A compatibility with version 1.6                        }
  38. {    01/30/90    Added "Tabby Log" switch to aid compatibility with E. Selberg    }
  39. {                    pgms & boosted text read buffer from 16K to 32K (v. 1.7).        }
  40. {    02/19/90    Fixed problem with not closing Config file (v. 1.8)    .                }
  41. {    02/27/90    Fixed bug with routing to AreaFix.                                    }
  42. {    05/04/90    Added ability to spot ff-processed [^p] messages and send        }
  43. {                    them to local private. STR  499 holds ff private flag                }
  44. {    07/02/90    Version 1.91 fixes bug which sent messages with missing         }
  45. {                    missing Subject: or To: line to local private.                        }
  46. {    07/16/90    Version 1.92 fixes bug which clipped point number from            }
  47. {                    message addresses.                                                        }
  48. {    07/16/90    Version 1.93 no longer sets "processed by Tabby" flag            }
  49. {                    which was messing up ff.                                                }
  50. {    10/28/90    Version 1.94 checks dates of messages for validity, adjusts    }
  51. {                    date and time to current date and time if fields are not valid.    }
  52. {    01/08/91    Version 1.95 adds TEXT type option field and Version                }
  53. {                    info in running dialog.                                                    }
  54. {    02/09/91    Version 1.96 breaks long Generic Import lines to user-set         }
  55. {                    length. Also handles capitalization for McNames correctly.        }
  56. {                    Eliminated AreaFix trapdoor since AreaTrix works differently    }
  57. {                    (pre-processes).                                                         }
  58. {    05/26/91    V 1.97 added SIZE resource and WaitNextEvents.                    }
  59. {    06/25/91    V 1.98 added option to count imports to sections.                    }
  60. {    06/27/91    V 2.0 cleaned up Tabby Log report, added color icons.            }
  61. {    07/05/91    V 2.0.1 fixed garbage in UNKNOWN message section name.        }
  62. {    07/05/91    V 2.0.2 various small fixes including adding Find button to        }
  63. {                    Config dialog.                                                            }
  64. {    09/07/91    V 2.0.3 increments mail byte for SS 2.0b11.                        }
  65.  
  66. {    This program imports messages to Second Sight using the Generic Tabby         }
  67. {    Message Format.                                                                        }
  68.  
  69.     uses
  70.         Globals, HelloTabby, FileUtils, ImpHostFile;
  71.  
  72.     const
  73.         Dashes = '---------------------------------------------------------------------';
  74.         MAXUSERS = 3000;
  75.         VERSION = '2.0.3';
  76.  
  77.     type
  78.         TimeRec = packed array[1..3] of char;
  79.         DayandHour = packed array[1..6] of char;
  80.         UserName = record
  81.                 Index: integer;
  82.                 Name: string[32];
  83.                 MailCount: byte;
  84.             end;
  85.         UserPointer = ^UserName;
  86.         UserHandle = ^UserPointer;
  87.         UserArray = array[1..MAXUSERS] of UserHandle;
  88.         Header = record
  89.                 Status: packed array[1..2] of Byte;    {    Use Status[1] only        }
  90.                 MsgNo: longint;
  91.                 Section: packed array[1..2] of Byte;    {    Use Section[1] only        }
  92.                 TimeRcvd: DayandHour;
  93.                 MsgFrom: string[31];
  94.                 MsgTo: string[31];
  95.                 MsgSubject: string[41];
  96.                 Destination: string[67];
  97.                 BeginText: longint;
  98.                 LengthText: longint;
  99.                 ReplyTo: longint;
  100.                 TimeSent: DayandHour
  101.             end;
  102.         HeaderPtr = ^Header;
  103.         HeaderHndl = ^HeaderPtr;
  104.         UserEntry = packed record
  105.                 FirstName: string[15];
  106.                 LastName: string[15];
  107.                 TheRest: packed array[1..104] of char;
  108.             end;
  109.         UserRecordPtr = ^UserEntry;
  110.         UserRecordHndl = ^UserRecordPtr;
  111.         DateOrTime = (Date, Time);
  112.         MessageSectName = array[1..255] of string[25];
  113.         MSectPtr = ^MessageSectName;
  114.  
  115.     var
  116.         ThisHeader: Header;
  117.         UserRecord: UserEntry;
  118.         ThisUserHandle: UserRecordHndl;
  119.         ThisUser: UserArray;
  120.         Unknown, MsgCount, Undeliverable, UnknownSection, LocalPrivate: integer;
  121.         Counter, MHdrRef, MTextRef, TLogRef, GenericRef, GenImpRef, LNRefNum: integer;
  122.         TempRefNum: integer;
  123.         Echoes, PrivNet: packed array[1..255] of boolean;
  124.         Done, UserExists, DeCapitalize, ErrorFlag: boolean;
  125.         Ms, TempString, PrivNetSect, TabbyString, PrivMark, LineLengthString: STR255;
  126.         SectionString, TheFileName, GenericPath, TheImportFile, SectionName: STR255;
  127.         PrivCat: string[4];
  128.         LastHiMsg, Range, EndOfFile, HowMuch, LaunchCount: longint;
  129.         Quantity, LogicalEOF, UserCount, PrivCatNum: longint;
  130.         DialogPointer: DialogPtr;
  131.         TheRect: rect;
  132.         TByte: SignedByte;
  133.         TabbyLog: boolean;
  134.         NextChar: char;
  135.         MNamePtr: MSectPtr;
  136.  
  137. { ------------------------------------------------------ }
  138.  
  139.     function WriteChars (FileRefNum: integer; TheMessage: string): OSErr;
  140.  
  141. { Function writes string to text file, returns error code           }
  142.  
  143.         var
  144.             TheLength: longint;
  145.  
  146.     begin
  147.         TheLength := length(TheMessage);
  148.         WriteChars := FSWrite(FileRefNum, TheLength, Pointer(ord(@TheMessage) + 1));
  149.     end;
  150.  
  151. {-----------------------------------------------------------------    }
  152.  
  153.     function WrLn (fRef: integer; theString: str255): OSErr;
  154.  
  155.     begin
  156.         Err := WriteChars(fRef, concat(theString, ENDLINE));
  157.     end;
  158.  
  159. {-----------------------------------------------------------------    }
  160.  
  161.     function ReadChars (FileRefNum, TheLength: longint): string;
  162.  
  163. { Function reads packed array of chars from text file, returns error code           }
  164.  
  165.         type
  166.             TheChars = packed array[1..255] of char;
  167.             TheCharsPtr = ^TheChars;
  168.             TheCharsHdl = ^TheCharsPtr;
  169.  
  170.         var
  171.             Counter: integer;
  172.             TheCharsHandle: TheCharsHdl;
  173.  
  174.     begin
  175.         TempString := '';
  176.         TheCharsHandle := TheCharsHdl(NewHandle(sizeOf(TheChars)));
  177.         Err := FSRead(FileRefNum, TheLength, Ptr(TheCharsHandle^));
  178.         for Counter := 1 to TheLength do
  179.             TempString := concat(TempString, TheCharsHandle^^[Counter]);
  180.         ReadChars := TempString;
  181.         DisposHandle(Handle(TheCharsHandle));
  182.     end;
  183.  
  184. {-----------------------------------------------------------------    }
  185.     function Int2Char (Number: integer): char;
  186.  
  187. { Function changes integer to character.                                }
  188.  
  189.     begin
  190.         Int2Char := chr(Number + ord('0'));
  191.     end;
  192.  
  193. { ------------------------------------------------------ }
  194.     function TwoDigit (Number: integer): string;
  195.  
  196. { Function changes two-digit number to a two-character string.           }
  197.  
  198.     begin
  199.         TwoDigit := concat(Int2Char(Number div 10), Int2Char(Number mod 10));
  200.     end;
  201.  
  202. { ------------------------------------------------------ }
  203.  
  204.     procedure TimeStamp;
  205.  
  206.         var
  207.             Today: DateTimeRec;
  208.             ASCIIHour: string;
  209.  
  210.     begin
  211.         GetTime(Today);
  212.  
  213. { The TwoDigit function in the following section turns a two-digit integer          }
  214. { into a two-character string. If there are fewer than two digits, the string    }
  215. { contains a leading '0'.                                                                              }
  216.  
  217.         ASCIIHour := TwoDigit(Today.Hour);            {    This bit of nonsense is to get the Tabby Log output        }
  218.         if length(ASCIIHour) > 1 then                    {    to match a Tabby convention: single-digit hours do        }
  219.             if (copy(ASCIIHour, 1, 1) = '0') then        {    not have leading zeroes, even though all other single        }
  220.                 ASCIIHour := copy(ASCIIHour, 2, 1);        {    digit numbers do.                                                }
  221.  
  222.         DateString := concat(TwoDigit(Today.Month), '/', TwoDigit(Today.Day), '/', TwoDigit(Today.Year - 1900));
  223.         TimeString := concat(ASCIIHour, ':', TwoDigit(Today.Minute), ':', TwoDigit(Today.Second));
  224.         DateString := concat(DateString, ' ', TimeString, ' ');
  225.     end;
  226.  
  227. { ------------------------------------------------------ }
  228.  
  229.     function GetWidth (number: integer): integer;
  230.  
  231.     begin
  232.         if number > 999 then
  233.             GetWidth := 4
  234.         else if number > 99 then
  235.             GetWidth := 3
  236.         else if number > 9 then
  237.             GetWidth := 2
  238.         else
  239.             GetWidth := 1
  240.     end;
  241.  
  242. {-----------------------------------------------------------------    }
  243.  
  244.     function ButtonSelected (whichDialog: DialogPtr; whichItem: integer): boolean;
  245.  
  246.         var
  247.             whichType: integer;
  248.             whichHandle: handle;
  249.             whichRect, displayRect: rect;
  250.             mouseLoc: point;
  251.             DelayTime: longint;
  252.             nowInverted: boolean;
  253.  
  254.     begin
  255.         getDItem(whichDialog, whichItem, whichType, whichHandle, whichRect);
  256.         displayRect := whichRect;
  257.         InsetRect(displayRect, 1, 1);
  258.         InvertRect(displayRect);
  259.         nowInverted := true;
  260.         if StillDown then
  261.             repeat
  262.                 GetMouse(mouseLoc);
  263.                 if PtInRect(mouseLoc, whichRect) then
  264.                     begin
  265.                         if not nowInverted then
  266.                             begin
  267.                                 InvertRect(displayRect);
  268.                                 nowInverted := true
  269.                             end
  270.                     end
  271.                 else
  272.                     begin
  273.                         if nowInverted then
  274.                             begin
  275.                                 InvertRect(displayRect);
  276.                                 nowInverted := false
  277.                             end
  278.                     end
  279.             until not StillDown;
  280.         if nowInverted then
  281.             begin
  282.                 Delay(4, DelayTime);
  283.                 InvertRect(displayRect);
  284.             end;
  285.         ButtonSelected := nowInverted
  286.     end;
  287.  
  288. {-----------------------------------------------------------------    }
  289.  
  290.     procedure HandleError;
  291.  
  292. {    Creates a dialog with a numeric error code        }
  293.  
  294.         var
  295.             theDialog: DialogPtr;
  296.             ItemHit, itemType: integer;
  297.             itemHandle: Handle;
  298.             dispRect: Rect;
  299.             ErrMessage: STR255;
  300.  
  301.     begin
  302.         DisposDialog(DialogPointer);
  303.         InitCursor;
  304.         theDialog := GetNewDialog(1003, nil, POINTER(-1));
  305.         SetPort(theDialog);
  306.         FrameDItem(theDialog, OK);
  307.         DrawDialog(theDialog);
  308.  
  309.         NumToString(ErrorCode, ErrMessage);
  310.         ErrMessage := concat('Error #', ErrMessage);
  311.         getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  312.         SetIText(Handle(itemHandle), ErrMessage);
  313.  
  314.         case ErrorCode of
  315.             1: 
  316.                 ErrMessage := 'Bad Private category number';
  317.             2: 
  318.                 ErrMessage := 'Bad DeCapitalize option';
  319.             3: 
  320.                 ErrMessage := 'Bad AreaFix name';
  321.             4: 
  322.                 ErrMessage := 'Couldn''t open Tabby Log';
  323.             5: 
  324.                 ErrMessage := 'Couldn''t close Tabby Log';
  325.             6: 
  326.                 ErrMessage := 'Problem with Generic file';
  327.             8: 
  328.                 ErrMessage := 'Problem with Generic Import file';
  329.             85, 500..507: 
  330.                 ErrMessage := 'Problem with Config file';
  331.             9: 
  332.                 ErrMessage := 'Problem with UserLog file';
  333.             10: 
  334.                 ErrMessage := 'Problem with UserLog';
  335.             11: 
  336.                 ErrMessage := 'Problem reading MESSAGES file';
  337.             12: 
  338.                 ErrMessage := 'Couldn''t process import file';
  339.             13: 
  340.                 ErrMessage := 'Problem reading MSGHDR or MSGTXT';
  341.  
  342.             otherwise
  343.                 ErrMessage := 'Undefined error';
  344.         end;
  345.  
  346.         ErrMessage := concat('Type: ', ErrMessage, '.');
  347.         getDItem(theDialog, 6, itemType, itemHandle, dispRect);
  348.         SetIText(Handle(itemHandle), ErrMessage);
  349.  
  350.         repeat
  351.             ModalDialog(nil, ItemHit);
  352.         until (ItemHit = 1);
  353.  
  354.         DisposDialog(theDialog);
  355.         ExitToShell;
  356.     end;
  357.  
  358. { ------------------------------------------------------ }
  359.  
  360.     procedure MemorizeUL;
  361.  
  362. {    Reads names from UserLog into an array of handles. UserCount holds number of users.        }
  363.  
  364.         var
  365.             HowBig, WhereNow, UserRecSize: longint;
  366.             Advance, ULogRef, Count: integer;
  367.  
  368.         procedure QuickSort (Start, Finish: integer; var TheArray: UserArray);
  369.  
  370. {    Sorts UserArray by name using QuickSort    }
  371.  
  372.             var
  373.                 Left, Right: integer;
  374.                 StarterValue: string[32];
  375.                 Temp: UserHandle;
  376.  
  377.         begin
  378.             Left := Start;
  379.             Right := Finish;
  380.             StarterValue := TheArray[(Start + Finish) div 2]^^.Name;    {    Pick a starter    }
  381.             repeat
  382.                 while TheArray[Left]^^.Name < StarterValue do
  383.                     Left := Left + 1;    {    Find a bigger value on the left    }
  384.                 while StarterValue < TheArray[Right]^^.Name do
  385.                     Right := Right - 1;    {    Find a smaller value on the right    }
  386.                 if Left <= Right then
  387.                     begin    {If we haven't gone too far...    }
  388.                         Temp := TheArray[Left];
  389.                         TheArray[Left] := TheArray[Right];
  390.                         TheArray[Right] := Temp;
  391.                         Left := Left + 1;
  392.                         Right := Right - 1
  393.                     end;    {    then    }
  394.             until Right <= Left;
  395.             if Start < Right then
  396.                 QuickSort(Start, Right, TheArray);
  397.             if Left < Finish then
  398.                 QuickSort(Left, Finish, TheArray);
  399.         end;    {    QuickSort    }
  400.  
  401.     begin
  402.         UserRecSize := 136;        {    Each UserLog entry is 136 bytes    }
  403.         ThisUserHandle := UserRecordHndl(NewHandle(sizeOf(UserEntry)));
  404.         Err := FSOpen(ULPath, vRefNum, ULogRef);
  405.         if Err = NoErr then
  406.             begin
  407.                 Err := GetEOF(ULogRef, HowBig);
  408.                 if Err = NoErr then
  409.                     begin
  410.                         UserCount := HowBig div UserRecSize;
  411.                         if UserCount > MAXUSERS then
  412.                             begin
  413.                                 Err := FSClose(ULogRef);
  414.                                 HandleError;
  415.                             end;
  416.                         Advance := HowBig div 5;
  417.                         if Advance = 0 then
  418.                             Advance := 1;
  419.                         Err := SetFPos(ULogRef, fsFromStart, 0);
  420.                         for Count := 1 to UserCount do
  421.                             begin
  422.                                 if MultiFinder then
  423.                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  424.                                 Err := FSRead(ULogRef, UserRecSize, Ptr(ThisUserHandle^));
  425.                                 with ThisUserHandle^^ do
  426.                                     begin
  427.                                         ThisUser[Count] := UserHandle(NewHandle(SizeOf(UserRecord)));
  428.                                         ThisUser[Count]^^.Index := Count;
  429.                                         ThisUser[Count]^^.Name := concat(FirstName, ' ', LastName);
  430.                                         ThisUser[Count]^^.MailCount := ord(TheRest[63]);
  431.                                     end;        {    with ThisUserHandle^^ do    }
  432.                                 if (Count mod Advance = 0) then
  433.                                     begin
  434.                                         TheRect.right := 26 + (Count div Advance);
  435.                                         PaintRect(TheRect)
  436.                                     end        {    if (Count mod Advance = 0)    }
  437.                             end;        {    for Count := 1 to UserCount    }
  438.                         Err := FSClose(ULogRef);
  439.                         TheRect.right := 31;
  440.                         PaintRect(TheRect);
  441.                         if MultiFinder then
  442.                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  443.                         QuickSort(1, UserCount, ThisUser);
  444.                         if MultiFinder then
  445.                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  446.                         DisposHandle(Handle(ThisUserHandle));
  447.                     end;        {    if Err = NoErr    }
  448.             end;        {    if Err = NoErr    }
  449.     end;
  450.  
  451. {-----------------------------------------------------------------    }
  452.  
  453.     function Pad (PadLength: integer): string;
  454.  
  455.         var
  456.             PadTemp: string;
  457.             PadCount: integer;
  458.  
  459.     begin
  460.         PadTemp := '';
  461.         for PadCount := 1 to PadLength do        {    line o' nulls        }
  462.             PadTemp := concat(PadTemp, chr(0));
  463.         Pad := PadTemp;
  464.     end;
  465.  
  466. {-----------------------------------------------------------------    }
  467.  
  468.     procedure UpdateUL (ToLine: STR255);
  469.  
  470.         var
  471.             Position, LoBound, HiBound, ULRef: integer;
  472.             ULRecSize, WhereToGo: longint;
  473.  
  474.     begin
  475.         ThisUserHandle := UserRecordHndl(NewHandle(sizeOf(UserEntry)));
  476.         UprString(ToLine, false);
  477.  
  478.         LoBound := 1;
  479.         HiBound := UserCount;
  480.  
  481.         repeat
  482.             Position := (LoBound + HiBound) div 2;
  483.             if (ToLine > ThisUser[Position]^^.Name) then
  484.                 LoBound := Position + 1
  485.             else
  486.                 HiBound := Position - 1
  487.         until (ToLine = ThisUser[Position]^^.Name) or (LoBound > HiBound);
  488.  
  489.         if (ToLine = ThisUser[Position]^^.Name) then
  490.             begin
  491.                 UserExists := true;
  492.                 if (ThisUser[Position]^^.MailCount < 255) then
  493.                     begin
  494.                         ThisUser[Position]^^.MailCount := succ(ThisUser[Position]^^.MailCount);
  495.                         ULRecSize := sizeOf(UserRecord);
  496.                         WhereToGo := ULRecSize * (ThisUser[Position]^^.Index - 1);
  497.                         Err := FSOpen(ULPath, vRefNum, ULRef);
  498.                         Err := SetFPos(ULRef, fsFromStart, WhereToGo);
  499.                         Err := FSRead(ULRef, ULRecSize, Ptr(ThisUserHandle^));
  500.                         ThisUserHandle^^.TheRest[63] := chr(ThisUser[Position]^^.MailCount mod 255);
  501.                         Err := SetFPos(ULRef, fsFromStart, WhereToGo);
  502.                         Err := FSWrite(ULRef, ULRecSize, Ptr(ThisUserHandle^));
  503.                         Err := FSClose(ULRef)
  504.                     end    {    if (ThisUser[Position]^^.MailCount < 255)    }
  505.             end;    {    ToLine = ThisUser[Position]^^.Name    }
  506.         DisposHandle(Handle(ThisUserHandle));
  507.     end;
  508.  
  509. { ------------------------------------------------------ }
  510.  
  511.     function DTRToTime (DTR: TimeRec; separator: char): string;
  512.  
  513. { Function changes three chars of DateTimeRecord to formatted time or date string    }
  514.  
  515.         var
  516.             MakeTimeString, LocalTemp: STR255;
  517.  
  518.     begin
  519.         LocalTemp := '';
  520.         NumToString(ord(DTR[1]), LocalTemp);
  521.         if length(LocalTemp) = 1 then
  522.             LocalTemp := concat('0', LocalTemp);
  523.         MakeTimeString := concat(LocalTemp, Separator);
  524.         NumToString(ord(DTR[2]), LocalTemp);
  525.         if length(LocalTemp) = 1 then
  526.             LocalTemp := concat('0', LocalTemp);
  527.         MakeTimeString := concat(MakeTimeString, LocalTemp, Separator);
  528.         NumToString(ord(DTR[3]), LocalTemp);
  529.         if length(LocalTemp) = 1 then
  530.             LocalTemp := concat('0', LocalTemp);
  531.         DTRToTime := concat(MakeTimeString, LocalTemp)
  532.     end;
  533.  
  534. {-----------------------------------------------------------------    }
  535.  
  536.     function MakeTime (TimeString: STR255; Mode: DateOrTime): TimeRec;
  537.  
  538. {    Function changes formatted time or date string to three chars of WK DateTimeRecord    }
  539. {    TimeString format is MM/DD/YY or HH:MM:SS                                                }
  540.  
  541.         var
  542.             Value: longint;
  543.             ACharacter, BCharacter, CCharacter, Separator: str255;
  544.             Today: DateTimeRec;
  545.             BadDate: boolean;
  546.  
  547.     begin
  548.         BadDate := false;
  549.         if Mode = Date then
  550.             Separator := '/'
  551.         else
  552.             Separator := ':';
  553.         if (length(TimeString) = 8) & (TimeString[3] = Separator) & (TimeString[6] = Separator) then
  554.             begin
  555.                 StringToNum(copy(TimeString, 1, 2), Value);            {Value is either Month or Hour}
  556.                 if (Mode = Date) then
  557.                     if ((Value < 1) | (Value > 12)) then
  558.                         BadDate := true;
  559.                 if (Mode = Time) then
  560.                     if ((Value < 0) | (Value > 23)) then
  561.                         BadDate := true;
  562.                 if not BadDate then
  563.                     begin
  564.                         ACharacter := chr(Value);
  565.                         StringToNum(copy(TimeString, 4, 2), Value);            {Value is either Day or Minute}
  566.                         if (Mode = Date) then
  567.                             if ((Value < 1) | (Value > 31)) then
  568.                                 BadDate := true;
  569.                         if (Mode = Time) then
  570.                             if ((Value < 0) | (Value > 59)) then
  571.                                 BadDate := true;
  572.                         if not BadDate then
  573.                             begin
  574.                                 BCharacter := chr(Value);
  575.                                 StringToNum(copy(TimeString, 7, 2), Value);            {Value is either Year or Second}
  576.                                 if (Mode = Date) then
  577.                                     if ((Value < 0) | (Value > 99)) then
  578.                                         BadDate := true;
  579.                                 if (Mode = Time) then
  580.                                     if ((Value < 0) | (Value > 59)) then
  581.                                         BadDate := true;
  582.                                 if not BadDate then
  583.                                     begin
  584.                                         CCharacter := chr(Value);
  585.                                         MakeTime := concat(ACharacter, BCharacter, CCharacter)
  586.                                     end        {    if CCharater was within range        }
  587.                             end    {    if BCharater was within range        }
  588.                     end    {    if ACharater was within range        }
  589.             end    {    if separators and length were OK        }
  590.         else
  591.             BadDate := true;
  592.         if BadDate then
  593.             begin
  594.                 GetTime(Today);
  595.                 if (Mode = Date) then
  596.                     begin
  597.                         ACharacter := chr(Today.Month);
  598.                         BCharacter := chr(Today.Day);
  599.                         CCharacter := chr(Today.Year mod 100);
  600.                         MakeTime := concat(ACharacter, BCharacter, CCharacter)
  601.                     end    {    (Mode = Date)    }
  602.                 else    {    (Mode = Time)    }
  603.                     begin
  604.                         ACharacter := chr(Today.Hour);
  605.                         BCharacter := chr(Today.Minute);
  606.                         CCharacter := chr(Today.Second);
  607.                         MakeTime := concat(ACharacter, BCharacter, CCharacter)
  608.                     end;    {    (Mode = Time)    }
  609.             end;        {    if BadDate    }
  610.     end;
  611.  
  612. {-----------------------------------------------------------------    }
  613.  
  614.     procedure DeCap (var TheName: str255);
  615.  
  616.         var
  617.             NameCount: integer;
  618.  
  619.         procedure HandleMcName (var McN: str255);    {Adjusts caps in names such as McNamara}
  620.  
  621.             var
  622.                 i: integer;
  623.  
  624.         begin
  625.             if (length(McN) > 2) then
  626.                 for i := 3 to length(McN) do
  627.                     if ((McN[i - 1] = 'c') & (McN[i - 2] = 'M') & (McN[i] in ['a'..'z'])) & ((i = 3) | (McN[i - 3] = ' ')) then
  628.                         McN[i] := chr(ord(McN[i]) - 32);
  629.         end;
  630.  
  631.     begin
  632.         UprString(TheName, false);
  633.         for NameCount := 2 to length(TheName) do        {    Convert name to caps & lower case    }
  634.             if (TheName[NameCount]) in ['A'..'Z'] then
  635.                 if (TheName[NameCount - 1] in ['A'..'Z', 'a'..'z']) then
  636.                     TheName[NameCount] := chr(ord(TheName[NameCount]) + 32);
  637.  
  638.         HandleMcName(TheName)
  639.     end;
  640.  
  641. {-----------------------------------------------------------------    }
  642.  
  643.     procedure CheckSysop (var ToString: string);
  644.  
  645. { Procedure converts 'Sysop' and 'System Operator' to local name for private NetMail        }
  646.  
  647.         var
  648.             SysopCount: integer;
  649.             TempName: STR255;
  650.  
  651.     begin
  652.         TempName := ToString;
  653.         UprString(TempName, false);
  654.         while copy(TempName, 1, 1) = ' ' do                                {    Strip leading blanks    }
  655.             TempName := copy(TempName, 2, length(TempName) - 1);
  656.         while copy(TempName, length(TempName), 1) = ' ' do            {    Skip trailing blanks    }
  657.             TempName := copy(TempName, 1, length(TempName) - 1);
  658.  
  659.         if (TempName = 'SYSTEM OPERATOR') or (TempName = 'SYSOP') or (TempName = 'ALL') then
  660.             ToString := SysopName
  661.     end;
  662.  
  663. { ------------------------------------------------------ }
  664.  
  665.     procedure WriteMText (TheString: string);
  666.  
  667. {    Procedure writes a message line to MSGTXT                                  }
  668.  
  669.         var
  670.             HowLong: longint;
  671.  
  672.     begin
  673.         HowLong := length(TheString) + 1;                            {    include its length byte    }
  674.         Err := FSWrite(MTextRef, HowLong, @TheString);
  675.     end;
  676.  
  677. { ------------------------------------------------------ }
  678.  
  679.     function Make2Digits (ConvertFrom: string): integer;
  680.  
  681. {    Converts two-character string into an ascii value        }
  682.  
  683.         var
  684.             Num1, Num2: integer;
  685.  
  686.     begin
  687.         Num1 := ord(ConvertFrom[1]) - ord('0');
  688.         Num2 := ord(ConvertFrom[2]) - ord('0');
  689.         Make2Digits := Num2 + (Num1 * 10)
  690.     end;
  691.  
  692. { ------------------------------------------------------ }
  693.  
  694.     procedure TReadMESSAGES;
  695.  
  696. { Procedure reads the MESSAGES file                                }
  697.  
  698.         var
  699.             MSCount, MSGRefNum: integer;
  700.             MsgByte: Byte;
  701.             MsgString: STR255;
  702.             CharsToSend: longint;
  703.  
  704.     begin
  705.         MNamePtr := MSectPtr(NewPtr(SizeOf(MessageSectName)));
  706.         MsgPath := '';
  707.         LocalPrivate := 0;
  708.         CharsToSend := 255;
  709.         Err := FSOpen(MESSAGESPath, vRefNum, MSGRefNum);
  710.         if Err = NoErr then
  711.             begin
  712.                 Err := FSRead(MSGRefNum, CharsToSend, @MsgString);
  713.                 if Err = NoErr then
  714.                     begin
  715.                         if (length(MsgString) > 0) then
  716.                             MsgPath := concat(MsgString, ':');
  717.                         CharsToSend := 4;
  718.                         Err := SetFPos(MSGRefNum, fsFromStart, 50);
  719.                         if Err = NoErr then
  720.                             begin
  721.                                 Err := FSRead(MSGRefNum, CharsToSend, @LowMsg);
  722.                                 Err := FSRead(MSGRefNum, CharsToSend, @HiMsg);
  723.  
  724.                                 Unknown := 255;
  725.                                 for MSCount := 1 to 255 do
  726.                                     begin
  727.                                         Err := SetFPos(MSGRefNum, fsFromStart, (62 + (MSCount - 1) * 36));
  728.                                         CharsToSend := 255;
  729.                                         Err := FSRead(MSGRefNum, CharsToSend, @SectionName);
  730.                                         MNamePtr^[MSCount] := SectionName;
  731.                                         UprString(SectionName, false);
  732.                                         if EqualString(SectionName, 'UNKNOWN', false, false) then
  733.                                             Unknown := MSCount;
  734.  
  735.                                         Err := SetFPos(MSGRefNum, fsFromStart, (97 + (MSCount - 1) * 36));
  736.                                         CharsToSend := 1;
  737.                                         Err := FSRead(MSGRefNum, CharsToSend, @MsgByte);
  738.  
  739.                                         MsgByte := MsgByte div 256;
  740.  
  741.                                         Echoes[MSCount] := false;
  742.                                         PrivNet[MSCount] := false;
  743.  
  744.                                         case MsgByte of
  745.                                             4: 
  746.                                                 Echoes[MSCount] := true;
  747.  
  748.                                             3: 
  749.                                                 PrivNet[MSCount] := true;
  750.  
  751.                                             1: 
  752.                                                 if LocalPrivate = 0 then
  753.                                                     LocalPrivate := MSCount;
  754.  
  755.                                             otherwise
  756.                                                 ;
  757.  
  758.                                         end;    {    case statement    }
  759.  
  760.                                     end;        {    for MSCount := 1 to 255 do    }
  761.  
  762.                                 Err := FSClose(MSGRefNum);
  763.                             end
  764.                     end
  765.             end
  766.     end;
  767.  
  768. { ------------------------------------------------------ }
  769.  
  770.     procedure ProcessImports;
  771.  
  772. { Procedure translates Generic Import contents to message files                            }
  773.  
  774.         var
  775.             FlagCount, Count1, Count2, TextLineLength, BlankPos, LineCounter, ThisStatus, MESSAGESRef: integer;
  776.             ThisSection, MsgStart, TextLength, NewMsg, HowLong, CharsToSend, FlagPos: longint;
  777.             FlagLine, CatLine, OriginLine, FromLine, ToLine, SubjectLine, TextLine, TempTime1, TempTime2: STR255;
  778.             TempLine, Temp1, Temp2, Temp3, TempOriginLine: STR255;
  779.             SentDateLine, SentTimeLine, RcvdDateLine, RcvdTimeLine: TimeRec;
  780.             Today: DateTimeRec;
  781.             AFixRef, PMLength, OriginCount, ArrayCount: integer;
  782.             ALongInt: longint;
  783.             ImportArray: array[1..255] of integer;
  784.  
  785.     begin
  786.         if MultiFinder then
  787.             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  788.         for ArrayCount := 1 to 255 do
  789.             ImportArray[ArrayCount] := 0;
  790.         TheFileName := concat(MsgPath, 'MSGHDR');
  791.         Err := FSOpen(concat(MsgPath, 'MSGHDR'), vRefNum, MHdrRef);
  792.         if Err = noErr then
  793.             begin
  794.                 Err := SetFPos(MHdrRef, fsFromLEOF, 0);    {    Set file position to logical end of file    }
  795.                 if Err = noErr then
  796.                     begin
  797.                         Err := FSOpen(concat(MsgPath, 'MSGTXT'), vRefNum, MTextRef);
  798.                         if Err = noErr then
  799.                             begin
  800.                                 Err := SetFPos(MTextRef, fsFromLEOF, 0);    {    Set file position to logical end of file    }
  801.                                 if Err = noErr then
  802.                                     begin
  803.                                         GetTime(Today);
  804.                                         RcvdDateLine := concat(chr(Today.Month), chr(Today.Day), chr(Today.Year - 1900));
  805.                                         RcvdTimeLine := concat(chr(Today.Hour), chr(Today.Minute), chr(Today.Second));
  806.  
  807.                                         Err := FSOpen(TheImportFile, vRefNum, GenImpRef);
  808.                                         if Err = NoErr then
  809.                                             Err := GetEOF(GenImpRef, InFileLength);
  810.                                         if (InFileLength > 0) & (Err = NoErr) then
  811.                                             begin
  812.                                                 Leftover := '';
  813.                                                 Range := InFileLength;
  814.                                                 Err := SetFPos(GenImpRef, fsFromStart, 0);
  815.                                                 BufferFilePos := 0;
  816.                                                 ImportPos := 0;
  817.                                                 InBuffHndl := BuffHndl(NewHandle(sizeOf(FileBuffer)));
  818.                                                 FillBuffer(GenImpRef);
  819.  
  820.                                                 while (ImportPos < InFileLength) do
  821.                                                     begin
  822.                                                         if MultiFinder then
  823.                                                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  824.                                                         MsgBody := false;
  825.                                                         TheRect.right := trunc(((100 * (ImportPos + 0.5)) / Range) + 31);
  826.                                                         PaintRect(TheRect);
  827.                                                         FlagPos := ImportPos;
  828.                                                         FlagLine := TReadALine(GenImpRef);
  829.                                                         if length(FlagLine) <> 3 then
  830.                                                             begin
  831.                                                                 repeat
  832.                                                                     if MultiFinder then
  833.                                                                         IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  834.                                                                     TextLine := TReadALine(GenImpRef);
  835.                                                                 until (ImportPos >= (InFileLength - 1)) | (pos(chr(0), TextLine) > 0);
  836.                                                                 if pos(chr(0), TextLine) > 0 then
  837.                                                                     repeat
  838.                                                                         if MultiFinder then
  839.                                                                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  840.                                                                         Err := GetFPos(GenImpRef, FlagPos);
  841.                                                                         FlagLine := TReadALine(GenImpRef);
  842.                                                                     until (length(FlagLine) = 3) | (ImportPos >= (InFileLength - 1));
  843.                                                             end
  844.                                                         else if (FlagLine[1] <> 'D') & (ImportPos < InFileLength) then
  845.                                                             begin
  846.                                                                 MsgCount := succ(MsgCount);
  847.                                                                 Err := SetFPos(GenImpRef, fsFromStart, FlagPos);
  848.                                                                 FlagLine[1] := 'D';
  849.                                                                 Err := WriteChars(GenImpRef, concat(FlagLine, ENDLINE));
  850.                                                                 HiMsg := HiMsg + 1;
  851.                                                                 ThisStatus := 0;                        {    Originated on another system    }
  852.                                                                 if MultiFinder then
  853.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  854.                                                                 CatLine := TReadALine(GenImpRef);
  855.                                                                 StringToNum(CatLine, ThisSection);
  856.                                                                 if (ThisSection < 1) or (ThisSection > 255) then
  857.                                                                     ThisSection := Unknown;
  858.                                                                 if FlagLine[2] = 'M' then            {    Private NetMail message, otherwise it's an Echo        }
  859.                                                                     begin
  860.                                                                         ThisStatus := BitOr(ThisStatus, 4);
  861.                                                                         ThisSection := PrivCatNum;    {    Make sure it goes to Net Private    }
  862.                                                                     end
  863.                                                                 else if FlagLine[2] = 'E' then
  864.                                                                     begin
  865.                                                                         if not Echoes[ThisSection] then
  866.                                                                             ThisSection := Unknown;                {    Not a defined Echo -- send it to Unknown        }
  867.                                                                     end
  868.                                                                 else
  869.                                                                     ThisSection := Unknown;                    {    Wasn't 'E' or 'M' -- send it to Unknown        }
  870.                                                                 ImportArray[ThisSection] := succ(ImportArray[ThisSection]);
  871.                                                                 if MultiFinder then
  872.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  873.                                                                 TempTime1 := TReadALine(GenImpRef);
  874.                                                                 SentDateLine := MakeTime(TempTime1, Date);
  875.                                                                 TempTime2 := TReadALine(GenImpRef);
  876.                                                                 SentTimeLine := MakeTime(TempTime2, Time);
  877.                                                                 OriginLine := TReadALine(GenImpRef);
  878.                                                                 if MultiFinder then
  879.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  880.                                                                 FromLine := TReadALine(GenImpRef);
  881.                                                                 if length(FromLine) > 30 then
  882.                                                                     FromLine := copy(FromLine, 1, 30);
  883.                                                                 DeCap(FromLine);
  884.                                                                 ToLine := TReadALine(GenImpRef);
  885.                                                                 if length(ToLine) > 30 then
  886.                                                                     ToLine := copy(ToLine, 1, 30);
  887.                                                                 DeCap(ToLine);
  888.                                                                 if (FlagLine[2] = 'M') then    {    Private NetMail message    }
  889.                                                                     CheckSysop(ToLine);
  890.                                                                 if MultiFinder then
  891.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  892.                                                                 SubjectLine := TReadALine(GenImpRef);
  893.                                                                 if length(SubjectLine) > 40 then
  894.                                                                     SubjectLine := copy(SubjectLine, 1, 40);
  895. { if Subject or To line ends in PrivMark, it's a local private message marked by ff    }
  896.                                                                 PMLength := length(PrivMark);
  897.                                                                 if (pos(PrivMark, SubjectLine) > 0) | (pos(PrivMark, ToLine) > 0) then
  898.                                                                     if (pos(PrivMark, SubjectLine) = length(SubjectLine) - PMLength + 1) | (pos(PrivMark, ToLine) = length(ToLine) - PMLength + 1) then
  899.                                                                         begin
  900.                                                                             ThisStatus := BitXor(ThisStatus, 64);    {Don't say it originated elsewhere}
  901.                                                                             ThisSection := LocalPrivate;    {    Make sure it goes to Local Private    }
  902.                                                                             if (pos(PrivMark, SubjectLine) = length(SubjectLine) - PMLength + 1) then
  903.                                                                                 SubjectLine := copy(SubjectLine, 1, length(SubjectLine) - PMLength);
  904.                                                                             if (pos(PrivMark, ToLine) = length(ToLine) - PMLength + 1) then
  905.                                                                                 ToLine := copy(ToLine, 1, length(ToLine) - PMLength)
  906.                                                                         end;
  907.                                                                 UserExists := false;
  908.                                                                 if ToLine <> 'All' then
  909.                                                                     UpdateUL(ToLine);        {    Let addressee know there's mail waiting    }
  910.                                                                 if MultiFinder then
  911.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  912.                                                                 Err := GetFPos(MTextRef, MsgStart);    {    Use for pointer in MSGHDR and to compute length of text    }
  913.                                                                 if (not UserExists) and (FlagLine[2] = 'M') then    {    Undeliverable private NetMail    }
  914.                                                                     begin
  915.                                                                         if MultiFinder then
  916.                                                                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  917.                                                                         Temp1 := ToLine;
  918.                                                                         Temp2 := FromLine;
  919.                                                                         Temp3 := SubjectLine;
  920.                                                                         ThisSection := PrivCatNum;        {    Change section to Net Private        }
  921.                                                                         ToLine := SysopName;
  922.                                                                         FromLine := 'That Darned TImport';
  923.                                                                         SubjectLine := 'Undelivered NetMail';
  924.                                                                         WriteMText(' ');
  925.                                                                         WriteMText(Dashes);
  926.                                                                         WriteMText('    The following private NetMail message could not be delivered.');
  927.                                                                         WriteMText(Dashes);
  928.                                                                         WriteMText(' ');
  929.                                                                         WriteMText(concat('To: ', Temp1, '   From: ', Temp2));
  930.                                                                         WriteMText(concat('Subject: ', Temp3));
  931.                                                                         Temp1 := DTRToTime(SentDateLine, '/');
  932.                                                                         Temp2 := DTRToTime(SentTimeLine, ':');
  933.                                                                         WriteMText(concat('Date Sent: ', Temp1, ' at ', Temp2, '   Origin: ', OriginLine));
  934.                                                                         WriteMText(' ');
  935.                                                                         SentDateLine := RcvdDateLine;    {    Change date of this message to *now*    }
  936.                                                                         SentTimeLine := RcvdTimeLine;
  937.                                                                         LineCounter := 9
  938.                                                                     end
  939.                                                                 else
  940.                                                                     LineCounter := 0;
  941.                                                                 MsgBody := true;
  942.                                                                 repeat
  943.                                                                     TextLine := TReadALine(GenImpRef);
  944.                                                                     if (FlagLine[2] = 'M') & (pos(concat(CTLA, 'FMPT '), TextLine) = 1) then            {    Origin is a point    }
  945.                                                                         begin
  946.                                                                             TempOriginLine := concat(OriginLine, '.', copy(TextLine, 7, length(TextLine)));
  947.                                                                             OriginLine := '';
  948.                                                                             for OriginCount := 1 to length(TempOriginLine) do
  949.                                                                                 if TempOriginLine[OriginCount] in ['.', ':', '/', '0'..'9'] then
  950.                                                                                     OriginLine := concat(OriginLine, TempOriginLine[OriginCount])
  951.                                                                         end
  952.                                                                     else if (pos(NULL, TextLine) = 0) then
  953.                                                                         begin
  954.                                                                             if length(TextLine) < 2 then
  955.                                                                                 TextLine := concat(TextLine, '  ');
  956.                                                                             WriteMText(TextLine);
  957.                                                                             LineCounter := LineCounter + 1
  958.                                                                         end;        {    if (pos(chr(0), TextLine) = 0)        }
  959.                                                                 until (ImportPos >= (InFileLength - 1)) | (pos(chr(0), TextLine) > 0) | (LineCounter = 400);
  960.                                                                 MsgBody := false;
  961.                                                                 if (pos(chr(0), TextLine) = 0) & (ImportPos < InFileLength - 1) then
  962.                                                                     repeat
  963.                                                                         if MultiFinder then
  964.                                                                             IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  965.                                                                         TextLine := TReadALine(GenImpRef);
  966.                                                                     until (ImportPos >= (InFileLength - 1)) or (pos(chr(0), TextLine) > 0);
  967.  
  968.                                                                 if (LineCounter = 0) then
  969.                                                                     WriteMText('     ***  No message text  ***');
  970.  
  971.                                                                 Err := GetFPos(MTextRef, NewMsg);
  972.                                                                 TextLength := NewMsg - MsgStart;
  973.  
  974.                                                                 if MultiFinder then
  975.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  976.                                                                 with ThisHeader do
  977.                                                                     begin
  978.                                                                         MsgFrom := Pad(31);            {    write nulls to the name fields for easier viewing    }
  979.                                                                         MsgTo := Pad(31);                {    with FEdit                                                }
  980.                                                                         MsgSubject := Pad(41);
  981.                                                                         Destination := Pad(67);
  982.                                                                         HowLong := 206;                {    length of MSGHDR                                        }
  983.                                                                         Err := FSWrite(MHdrRef, HowLong, @ThisHeader);
  984.                                                                         Err := SetFPos(MHdrRef, fsFromLEOF, -206);
  985.                                                                         Status[1] := ThisStatus;
  986.                                                                         Status[2] := 0;
  987.                                                                         MsgNo := HiMsg;
  988.                                                                         Section[1] := ThisSection;
  989.                                                                         Section[2] := 0;
  990.                                                                         MsgFrom := FromLine;
  991.                                                                         MsgTo := ToLine;
  992.                                                                         MsgSubject := SubjectLine;
  993.                                                                         Destination := OriginLine;
  994.                                                                         BeginText := MsgStart;
  995.                                                                         LengthText := TextLength;
  996.                                                                         ReplyTo := 0;
  997.                                                                         TimeSent := concat(SentDateLine, SentTimeLine);
  998.                                                                         TimeRcvd := concat(RcvdDateLine, RcvdTimeLine);
  999.                                                                     end;        {    with ThisHeader    }
  1000.                                                                 Err := FSWrite(MHdrRef, HowLong, @ThisHeader);
  1001.  
  1002.                                                                 if MultiFinder then
  1003.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  1004.                                                                 Err := FSOpen(MESSAGESPath, vRefNum, MESSAGESRef);
  1005.                                                                 Err := SetFPos(MESSAGESRef, fsFromStart, 54);
  1006.                                                                 CharsToSend := 4;
  1007.                                                                 Err := FSWrite(MESSAGESRef, CharsToSend, @HiMsg);
  1008.                                                                 Err := GetFPos(MTextRef, MSGTXTLength);
  1009.                                                                 CharsToSend := 4;
  1010.                                                                 Err := FSWrite(MESSAGESRef, CharsToSend, @MSGTXTLength);
  1011.                                                                 Err := FSClose(MESSAGESRef)
  1012.                                                             end    {    (FlagLine[1] <> 'D') & (ImportPos < InFileLength)    }
  1013.                                                         else if (ImportPos < InFileLength) then
  1014.                                                             repeat
  1015.                                                                 if MultiFinder then
  1016.                                                                     IgnoreBool := WaitNextEvent(EveryEvent, TabbyEventRec, sleep, nil);
  1017.                                                                 TextLine := TReadALine(GenImpRef);
  1018.                                                             until (ImportPos >= (InFileLength - 1)) or (pos(chr(0), TextLine) > 0);
  1019.                                                     end;        {    while not eof(TabbyGeneric)    }
  1020.                                                 DisposHandle(Handle(InBuffHndl));
  1021.                                                 if SectCount then
  1022.                                                     begin
  1023.                                                         TimeStamp;
  1024.                                                         Err := FSOpen(concat(gDefaultPath, 'Tabby:Tabby Log'), vRefNum, TLogRef);
  1025.                                                         Err := SetFPos(TLogRef, fsFromLEOF, 0);
  1026.                                                         for ArrayCount := 1 to 255 do
  1027.                                                             if ImportArray[ArrayCount] > 0 then
  1028.                                                                 begin
  1029.                                                                     if ImportArray[ArrayCount] = 1 then
  1030.                                                                         Err := WrLn(TLogRef, concat(DateString, 'TImport - ', StringOf(ImportArray[ArrayCount] : GetWidth(MsgCount)), ' Message for ', MNamePtr^[ArrayCount], ' #', StringOf(ArrayCount : 1)))
  1031.                                                                     else
  1032.                                                                         Err := WrLn(TLogRef, concat(DateString, 'TImport - ', StringOf(ImportArray[ArrayCount] : GetWidth(MsgCount)), ' Messages for ', MNamePtr^[ArrayCount], ' #', StringOf(ArrayCount : 1)));
  1033.                                                                 end;
  1034.                                                         Err := FSClose(TLogRef);
  1035.                                                     end;    {if SectionCount}
  1036.                                             end;        {    InFileLength > 0    }
  1037.                                         Err := FSClose(GenImpRef);
  1038.                                         Err := FSDelete(TheImportFile, vRefNum);
  1039.                                         TheRect.right := 131;
  1040.                                         PaintRect(TheRect);
  1041.                                     end;            {    no error on SetFPos for MSGTXT    }
  1042.                             end;            {    no error on open MSGTXT    }
  1043.                         Err := FSClose(MTextRef);
  1044.                     end;            {    no error on SetFPos for MSGHDR    }
  1045.             end;        {    no error on open MSGHDR    }
  1046.         Err := FSClose(MHdrRef);
  1047.         if MNamePtr <> nil then
  1048.             begin
  1049.                 DisposPtr(Pointer(MNamePtr));
  1050.                 MNamePtr := nil
  1051.             end
  1052.     end;
  1053.  
  1054. { ------------------------------------------------------ }
  1055.  
  1056.     procedure HandleDialog;
  1057.  
  1058.         var
  1059.             theDialog: DialogPtr;
  1060.             ItemHit, itemType, whichItem, CheckCount: integer;
  1061.             itemHandle: Handle;
  1062.             dispRect: Rect;
  1063.             thisButton: ControlHandle;
  1064.             JustChecking: longint;
  1065.             ValidNumber: boolean;
  1066.             where: point;
  1067.             fileReply: SFReply;
  1068.             whatToFind: SFTypeList;
  1069.  
  1070.     begin
  1071.         InitCursor;
  1072.         theDialog := GetNewDialog(1002, nil, POINTER(-1));                {IM I-413}
  1073.         SetPort(theDialog);
  1074.         FrameDItem(theDialog, Ok);
  1075.         DrawDialog(theDialog);
  1076.  
  1077.         NextLaunch := GetString(500)^^;        {    Get next launch string from resource    }
  1078.         getDItem(theDialog, 3, itemType, itemHandle, dispRect);
  1079.         SetIText(Handle(itemHandle), NextLaunch);
  1080.  
  1081.         getDItem(theDialog, 4, itemType, itemHandle, dispRect);
  1082.         SetIText(Handle(itemHandle), PrivCat);
  1083.  
  1084.         getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  1085.         thisButton := ControlHandle(itemHandle);
  1086.         if DeCapitalize then
  1087.             SetCtlValue(thisButton, 1)
  1088.         else
  1089.             SetCtlValue(thisButton, 0);
  1090.  
  1091.         getDItem(theDialog, 6, itemType, itemHandle, dispRect);
  1092.         SetIText(Handle(itemHandle), LineLengthString);
  1093.  
  1094.         getDItem(theDialog, 17, itemType, itemHandle, dispRect);
  1095.         thisButton := ControlHandle(itemHandle);
  1096.         if TabbyLog then
  1097.             SetCtlValue(thisButton, 1)
  1098.         else
  1099.             SetCtlValue(thisButton, 0);
  1100.  
  1101.         getDItem(theDialog, 20, itemType, itemHandle, dispRect);
  1102.         SetIText(Handle(itemHandle), CreatorType);
  1103.  
  1104.         getDItem(theDialog, 23, itemType, itemHandle, dispRect);
  1105.         thisButton := ControlHandle(itemHandle);
  1106.         if SectCount then
  1107.             SetCtlValue(thisButton, 1)
  1108.         else
  1109.             SetCtlValue(thisButton, 0);
  1110.  
  1111.         TextFont(Geneva);
  1112.         TextSize(9);
  1113.         ForeColor(redColor);
  1114.         getDItem(theDialog, 14, itemType, itemHandle, dispRect);
  1115.         SetIText(Handle(itemHandle), VERSION);
  1116.         ForeColor(blackColor);
  1117.         SetDAFont(0);
  1118.         TextFont(0);
  1119.         TextSize(0);
  1120.  
  1121.         if StillDown then
  1122.             repeat
  1123.             until not Button;
  1124.         repeat
  1125.             ModalDialog(nil, ItemHit);                                            {IM I-415}
  1126.             ;
  1127.             case ItemHit of
  1128.  
  1129.                 1: { OK button hit -- save resources }
  1130.                     begin
  1131.                         getDItem(theDialog, 3, itemType, itemHandle, dispRect);
  1132.                         GetIText(Handle(itemHandle), NextLaunch);
  1133.                         RmveResource(GetResource('STR ', 500));
  1134.                         UpdateResFile(CurrentResFile);
  1135.                         AddResource(Handle(NewString(NextLaunch)), 'STR ', 500, 'Next Launch');
  1136.  
  1137.                         getDItem(theDialog, 4, itemType, itemHandle, dispRect);
  1138.                         GetIText(Handle(itemHandle), PrivNetSect);
  1139.                         ValidNumber := true;
  1140.                         for CheckCount := 1 to length(PrivNetSect) do
  1141.                             if not (PrivNetSect[CheckCount] in ['0'..'9', ' ']) then
  1142.                                 ValidNumber := false;
  1143.                         StringToNum(PrivNetSect, JustChecking);
  1144.                         if (JustChecking > 0) and (JustChecking < 256) and ValidNumber then
  1145.                             begin
  1146.                                 RmveResource(GetResource('STR ', 501));
  1147.                                 UpdateResFile(CurrentResFile);
  1148.                                 AddResource(Handle(NewString(PrivNetSect)), 'STR ', 501, 'PrivNetMail')
  1149.                             end
  1150.                         else
  1151.                             sysbeep(10);        {    Non-valid message section entered -- do nothing    }
  1152.  
  1153.                         tempString := 'NN';
  1154.                         if DeCapitalize then
  1155.                             TempString[1] := 'Y';
  1156.                         if SectCount then
  1157.                             TempString[2] := 'Y';
  1158.                         RmveResource(GetResource('STR ', 502));
  1159.                         UpdateResFile(CurrentResFile);
  1160.                         AddResource(Handle(NewString(TempString)), 'STR ', 502, 'Defaults');
  1161.  
  1162.                         getDItem(theDialog, 6, itemType, itemHandle, dispRect);
  1163.                         GetIText(Handle(itemHandle), LineLengthString);
  1164.                         RmveResource(GetResource('STR ', 503));
  1165.                         UpdateResFile(CurrentResFile);
  1166.                         AddResource(Handle(NewString(LineLengthString)), 'STR ', 503, 'Line Length');
  1167.  
  1168.                         if TabbyLog then
  1169.                             TempString := 'Y'
  1170.                         else
  1171.                             TempString := 'N';
  1172.                         RmveResource(GetResource('STR ', 504));
  1173.                         UpdateResFile(CurrentResFile);
  1174.                         AddResource(Handle(NewString(TempString)), 'STR ', 504, 'Tabby Log? (Y/N)');
  1175.  
  1176.                         getDItem(theDialog, 20, itemType, itemHandle, dispRect);
  1177.                         GetIText(Handle(itemHandle), CreatorType);
  1178.                         RmveResource(GetResource('STR ', 505));
  1179.                         UpdateResFile(CurrentResFile);
  1180.                         AddResource(Handle(NewString(CreatorType)), 'STR ', 505, 'TEXT Creator');
  1181.  
  1182.                     end;
  1183.  
  1184.                 2: 
  1185.                     ; { Cancel button hit—do nothing    }
  1186.  
  1187.                 5: 
  1188.                     begin { DeCapitalize switch    }
  1189.                         DeCapitalize := not DeCapitalize;
  1190.                         getDItem(theDialog, 5, itemType, itemHandle, dispRect);
  1191.                         thisButton := ControlHandle(itemHandle);
  1192.                         if DeCapitalize then
  1193.                             SetCtlValue(thisButton, 1)
  1194.                         else
  1195.                             SetCtlValue(thisButton, 0);
  1196.                     end;
  1197.  
  1198.                 17: 
  1199.                     begin { Tabby switch    }
  1200.                         TabbyLog := not TabbyLog;
  1201.                         getDItem(theDialog, 17, itemType, itemHandle, dispRect);
  1202.                         thisButton := ControlHandle(itemHandle);
  1203.                         if TabbyLog then
  1204.                             SetCtlValue(thisButton, 1)
  1205.                         else
  1206.                             SetCtlValue(thisButton, 0);
  1207.                     end;
  1208.  
  1209.                 23: 
  1210.                     begin { SectionCount switch    }
  1211.                         SectCount := not SectCount;
  1212.                         getDItem(theDialog, 23, itemType, itemHandle, dispRect);
  1213.                         thisButton := ControlHandle(itemHandle);
  1214.                         if SectCount then
  1215.                             SetCtlValue(thisButton, 1)
  1216.                         else
  1217.                             SetCtlValue(thisButton, 0);
  1218.                     end;
  1219.  
  1220.                 24:  { Choose Next Launch    }
  1221.                     if ButtonSelected(theDialog, 24) then
  1222.                         begin
  1223.                             where.h := 60;
  1224.                             where.v := 80;
  1225.                             whatToFind[0] := 'APPL';
  1226.                             ParamText('next application to launch', '', '', '');
  1227.                             SFGetFile(where, '', nil, 1, whatToFind, nil, fileReply);
  1228.                             if fileReply.good then
  1229.                                 begin
  1230.                                     getDItem(theDialog, 3, itemType, itemHandle, dispRect);
  1231.                                     NextLaunch := fileReply.fName;
  1232.                                     SetIText(Handle(itemHandle), NextLaunch)
  1233.                                 end;
  1234.                             FrameDItem(theDialog, Ok);
  1235.                         end;
  1236.  
  1237.                 otherwise
  1238.                     ;    {    do nothing    }
  1239.  
  1240.             end;
  1241.         until (ItemHit = 1) or (ItemHit = 2);
  1242.  
  1243.         DisposDialog(theDialog)
  1244.     end;
  1245.  
  1246. { ------------------------------------------------------ }
  1247.  
  1248.     var
  1249.         itemType: integer;
  1250.         itemHandle: handle;
  1251.         dispRect: rect;
  1252.         oldPort: GrafPtr;
  1253.  
  1254. begin
  1255.     MaxApplZone;
  1256.     GetPort(oldPort);
  1257.     ErrorFlag := false;
  1258.     ErrorCode := 0;
  1259.     CurrentResFile := CurResFile;
  1260.     PrivMark := GetString(499)^^;
  1261.     PrivCat := GetString(501)^^;
  1262.     StringToNum(PrivCat, PrivCatNum);
  1263.     ErrorCode := 1;
  1264.     TempString := GetString(502)^^;
  1265.     ErrorCode := 2;
  1266.     UprString(TempString, false);
  1267.     if TempString[1] = 'Y' then
  1268.         DeCapitalize := true
  1269.     else
  1270.         DeCapitalize := false;
  1271.     if TempString[2] = 'Y' then
  1272.         SectCount := true
  1273.     else
  1274.         SectCount := false;
  1275.     LineLengthString := GetString(503)^^;
  1276.     StringToNum(LineLengthString, MaxMsgLine);
  1277.     if (MaxMsgLine < 50) | (MaxMsgLine > 90) then
  1278.         MaxMsgLine := 75;
  1279.     ErrorCode := 3;
  1280.     TabbyString := GetString(504)^^;
  1281.     if TabbyString[1] = 'Y' then
  1282.         TabbyLog := true
  1283.     else
  1284.         TabbyLog := false;
  1285.     CreatorType := GetString(505)^^;
  1286.     while length(CreatorType) < 4 do
  1287.         CreatorType := concat(CreatorType, ' ');
  1288.     CreatorType := copy(CreatorType, 1, 4);
  1289.  
  1290.     if Button then
  1291.         HandleDialog        { If user is holding down the mouse button, reconfigure and end }
  1292.     else
  1293.         begin
  1294.             ErrorCode := 4;
  1295.             MsgCount := 0;
  1296.             UnknownSection := 0;
  1297.             Undeliverable := 0;
  1298.             DialogPointer := GetNewDialog(1001, nil, POINTER(-1));
  1299.             DrawDialog(DialogPointer);
  1300.             SetPort(DialogPointer);
  1301.             ShowWindow(DialogPointer);
  1302.             TextFont(Geneva);
  1303.             TextSize(9);
  1304.             ForeColor(redColor);
  1305.             getDItem(DialogPointer, 2, itemType, itemHandle, dispRect);
  1306.             SetIText(itemHandle, VERSION);
  1307.             SetRect(TheRect, 26, 49, 131, 54);
  1308.             FrameRect(TheRect);
  1309.             HelloTabby;    { find out what's next on the launchpad }
  1310.             TimeStamp;
  1311.  
  1312.             if TabbyLog then
  1313.                 begin
  1314.                     Err := FSOpen(concat(gDefaultpath, 'Tabby:Tabby Log'), vRefNum, TLogRef);
  1315.                     if (Err <> NoErr) then
  1316.                         HandleError;
  1317.                     ErrorCode := 5;
  1318.  
  1319.                     if not ErrorFlag then
  1320.                         begin
  1321.                             Err := SetFPos(TLogRef, fsFromLEOF, 0);
  1322.                             if (Err <> NoErr) then
  1323.                                 HandleError;
  1324.                             TempString := concat(concat(DateString, 'TImport - Program Starting (v ', VERSION, ')', ENDLINE));
  1325.                             Err := WriteChars(TLogRef, TempString);
  1326.                             if (Err <> NoErr) then
  1327.                                 HandleError;
  1328.                             Err := FSClose(TLogRef);
  1329.                             if (Err <> NoErr) then
  1330.                                 HandleError;
  1331.                         end;        {    if not ErrorFlag    }
  1332.                 end;    {    if TabbyLog    }
  1333.  
  1334.             ErrorCode := 6;
  1335.  
  1336.             if (Err <> NoErr) then
  1337.                 HandleError;
  1338.  
  1339.             Err := FSOpen(concat(gDefaultpath, 'Generic'), vRefNum, GenericRef);
  1340.             if (Err <> NoErr) then
  1341.                 HandleError;
  1342.             if not ErrorFlag then
  1343.                 begin
  1344.                     Err := GetEOF(GenericRef, logicalEOF);
  1345.                     if (Err <> NoErr) then
  1346.                         HandleError;
  1347.                     if (logicalEOF > 0) & (ErrorFlag = false) then
  1348.                         begin
  1349.                             GenericPath := ReadChars(GenericRef, logicalEOF - 1);    {    subtract 1 to avoid LF    }
  1350.                             Err := FSClose(GenericRef);
  1351.                             if (Err <> NoErr) then
  1352.                                 HandleError
  1353.                         end
  1354.                     else
  1355.                         HandleError
  1356.                 end;        {    if not ErrorFlag    }
  1357.             ErrorCode := 7;
  1358.  
  1359.             if (Err <> NoErr) then
  1360.                 HandleError;
  1361.  
  1362.             if GenericPath[length(GenericPath)] <> ':' then
  1363.                 GenericPath := concat(GenericPath, ':');
  1364.             TheImportFile := concat(GenericPath, 'Generic Import');
  1365.             Err := FSOpen(TheImportFile, vRefNum, GenImpRef);
  1366.             ErrorCode := 8;
  1367.  
  1368.             if (Err = NoErr) then
  1369.                 begin
  1370.                     Err := GetEOF(GenImpRef, logicalEOF);
  1371.                     if (Err = NoErr) then
  1372.                         begin
  1373.                             Err := FSClose(GenImpRef);
  1374.                             if (Err = NoErr) | (logicalEOF > 0) then
  1375.                                 begin
  1376.                                     ErrorCode := 85;
  1377.                                     ReadConfig;
  1378.  
  1379.                                     if (Err <> NoErr) then
  1380.                                         HandleError;
  1381.  
  1382.                                     ErrorCode := 9;
  1383.  
  1384.                                     if DeCapitalize then
  1385.                                         DeCap(SysopName);
  1386.                                     MemorizeUL;
  1387.                                     ErrorCode := 10;
  1388.                                     if (Err <> NoErr) then
  1389.                                         HandleError;
  1390.                                     TReadMESSAGES;
  1391.                                     ErrorCode := 11;
  1392.                                     if (Err <> NoErr) then
  1393.                                         HandleError;
  1394.                                     ProcessImports;
  1395.                                     ErrorCode := 12;
  1396.                                     if (Err <> NoErr) then
  1397.                                         HandleError;
  1398.                                     for Counter := 1 to UserCount do
  1399.                                         DisposHandle(Handle(ThisUser[Counter]));
  1400.                                     ErrorCode := 13
  1401.                                 end            {    Closed Generic Import OK    }
  1402.                         end            {    Got EOF of Generic Import OK    }
  1403.                 end;        {    Opened Generic Import OK    }
  1404.             TimeStamp;
  1405.             if TabbyLog then
  1406.                 begin
  1407.                     Err := FSOpen(concat(gDefaultpath, 'Tabby:Tabby Log'), vRefNum, TLogRef);
  1408.                     Err := SetFPos(TLogRef, fsFromLEOF, 0);
  1409.                     NumToString(MsgCount, TempString);
  1410.                     if MsgCount > 0 then
  1411.                         begin
  1412.                             if MsgCount = 1 then
  1413.                                 TempString := concat(DateString, 'TImport - ', StringOf(MsgCount : GetWidth(MsgCount)), ' Message Total')
  1414.                             else
  1415.                                 TempString := concat(DateString, 'TImport - ', StringOf(MsgCount : GetWidth(MsgCount)), ' Messages Total');
  1416.                             Err := WrLn(TLogRef, TempString)
  1417.                         end;
  1418.                     if Undeliverable > 0 then
  1419.                         begin
  1420.                             NumToString(Undeliverable, TempString);
  1421.                             TempString := concat(DateString, 'TImport - Error: ', TempString, ' Private Net Messages were Undeliverable');
  1422.                             Err := WrLn(TLogRef, TempString)
  1423.                         end;
  1424.                     if UnknownSection > 0 then
  1425.                         begin
  1426.                             NumToString(UnknownSection, TempString);
  1427.                             TempString := concat(DateString, 'TImport - Error: ', TempString, ' Public Net Messages sent to Unknown Section');
  1428.                             Err := WrLn(TLogRef, TempString);
  1429.                         end;
  1430.                     Err := WrLn(TLogRef, concat(DateString, 'TImport - Program Ending'));
  1431.                     Err := FSClose(TLogRef)
  1432.                 end;    {    if TabbyLog    }
  1433.  
  1434.             DisposDialog(DialogPointer);
  1435.             SetPort(oldPort);
  1436.             if NextLaunch <> '' then
  1437.                 LaunchNextAppl
  1438.         end        {    if not Button        }
  1439. end.        {    procedure    }